package com.qd.system.importexcel.menu;

import com.alibaba.excel.read.metadata.holder.ReadRowHolder;
import com.cdqidi.dto.BatchResult;
import com.cdqidi.excel.domain.ExcelRowMsg;
import com.cdqidi.excel.domain.ImportErr;
import com.cdqidi.excel.util.ExcelUtil;
import com.cdqidi.exception.ExcelOperatorException;
import com.cdqidi.util.ValidatorUtil;
import com.cdqidi.valid.group.DefaultGroup;
import com.qd.common.sys.domain.entity.meun.MenuDTO;
import com.qd.common.sys.enums.BaseTableEnum;
import com.qd.system.model.Menu;
import com.qd.system.service.dict.ExcelValidateUtil;
import com.qd.system.service.dict.MbUtil;
import com.qd.system.service.menu.MenuService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.util.StringUtils;

import javax.validation.ConstraintViolationException;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;

import static java.util.stream.Collectors.toList;

/**
 * 菜单,excel导入处理类
 *
 * @author sjk
 */
@Slf4j
@RequiredArgsConstructor
public class MenuImportHandler {

    private final MenuService menuService;
    private final ValidatorUtil validatorUtil;
    private final List<ImportErr> errorList;

    private final LocalDateTime now = LocalDateTime.now();
    private final ExcelValidateUtil excelValidateUtil = new ExcelValidateUtil();

    /**
     * 处理具体导入
     *
     * @param rowList excel行数据集合，默认为1000行
     * @param results 异常信息存储
     */
    public void process(List<ExcelRowMsg<MenuDTO>> rowList, List<BatchResult> results) {
        final List<MenuDTO> menuList = rowList.stream().map(ExcelRowMsg::getRowData).collect(toList());
        final List<String> existsIds = existsIds(menuList);
        final int size = rowList.size();
        try {
            for (ExcelRowMsg<MenuDTO> excelRowMsg : rowList) {
                final MenuDTO menuDTO = excelRowMsg.getRowData();
                final ReadRowHolder readRowHolder = excelRowMsg.getReadRowHolder();
                final List<String> errors = buildImportDTO(menuDTO);
                if (!errors.isEmpty()) {
                    errorList.add(ExcelUtil.buildError(readRowHolder, errors));
                }
            }
            if (!errorList.isEmpty()) {
                throw new ExcelOperatorException(errorList);
            } else {
                final List<Menu> addMenuList = new ArrayList<>(size);
                final List<Menu> updateMenuList = new ArrayList<>(size);
                doProcessDictData(existsIds, menuList, addMenuList, updateMenuList);
                BatchResult.buildBatchResult(results, addMenuList.size(), updateMenuList.size());
                addMenuList.clear();
                updateMenuList.clear();
            }
        } finally {
            menuList.clear();
            existsIds.clear();
        }
    }

    /**
     * 保存数据
     *
     * @param existsIds      已经存在的数据库主键
     * @param menuList       excel行数据集合
     * @param addMenuList    添加集合
     * @param updateMenuList 更新集合
     */
    private void doProcessDictData(List<String> existsIds, List<MenuDTO> menuList, List<Menu> addMenuList, List<Menu> updateMenuList) {
        menuList.forEach(menuDTO -> {
            final Menu menu = menuService.dtoToModel(menuDTO);
            menuService.clearCache(menu);
            if (MbUtil.isExistInCollection(existsIds, menuDTO.getMenuId())) {
                menu.setAddTime(null);
                menu.setUpdateTime(now);
                updateMenuList.add(menu);
            } else {
                menu.setAddTime(now);
                menu.setUpdateTime(null);
                addMenuList.add(menu);
            }
        });
        if (!addMenuList.isEmpty()) {
            menuService.saveBatch(addMenuList);
        }
        if (!updateMenuList.isEmpty()) {
            menuService.updateBatchIds(updateMenuList);
        }
    }

    /**
     * 获得主键存在的集合
     *
     * @param menuList excel行数据集合
     * @return 主键集合
     */
    private List<String> existsIds(List<MenuDTO> menuList) {
        final List<String> ids = menuList.stream().map(MenuDTO::getMenuId).collect(toList());
        final List<String> existsIds = menuService.getBaseMapper().getIds(ids);
        ids.clear();
        return existsIds;
    }

    /**
     * 导入验证
     *
     * @param menuDTO 单个excel行数据
     * @return 异常信息
     */
    private List<String> buildImportDTO(MenuDTO menuDTO) {
        final List<String> errors = new ArrayList<>();
        if (StringUtils.hasLength(menuDTO.getMenuStatusDisplay())) {
            final Integer menuStatus = MbUtil.isStatusValidate(errors, menuDTO.getMenuStatusDisplay());
            if (null != menuStatus) {
                menuDTO.setMenuStatus(menuStatus);
            }
        }
        if (StringUtils.hasLength(menuDTO.getVisibleDisplay())) {
            final String visible = excelValidateUtil.isValidBase(menuDTO.getVisibleDisplay(), BaseTableEnum.VISIBLE, errors);
            if (StringUtils.hasLength(visible)) {
                menuDTO.setVisible(visible);
            }
        }
        if (StringUtils.hasLength(menuDTO.getMenuTypeDisplay())) {
            final String menuType = excelValidateUtil.isValidBase(menuDTO.getMenuTypeDisplay(), BaseTableEnum.MENU_TYPE, errors);
            if (StringUtils.hasLength(menuType)) {
                menuDTO.setMenuType(menuType);
            }
        }
        if(StringUtils.hasLength(menuDTO.getButtonTypeDisplay())){
            final String buttonType = excelValidateUtil.isValidBase(menuDTO.getButtonTypeDisplay(), BaseTableEnum.BUTTON_TYPE, errors);
            if (StringUtils.hasLength(buttonType)) {
                menuDTO.setButtonType(buttonType);
            }
        }
        if(StringUtils.hasLength(menuDTO.getIsFrameDisplay())){
            final String isFrame = excelValidateUtil.isValidBase(menuDTO.getIsFrameDisplay(), BaseTableEnum.SF, errors);
            if (StringUtils.hasLength(isFrame)) {
                menuDTO.setIsFrame(isFrame);
            }
        }
        //验证信息，自己编写
        importValidate(menuDTO, errors);
        return errors;
    }

    /**
     * 导入实体验证
     *
     * @param menuDTO 单个excel行数据
     * @param errors  异常信息存储
     */
    private void importValidate(MenuDTO menuDTO, List<String> errors) {
        if (errors.isEmpty()) {
            try {
                validatorUtil.checkValid(menuDTO, DefaultGroup.class);
            } catch (ConstraintViolationException e) {
                errors.addAll(validatorUtil.getValidationError(e));
            }
        }
    }
}